#include "error.h"

namespace Pbrt
{
    static std::string StringVaprintf
    (const std::string& msg, va_list args)
    {
        //std::cout << __PRETTY_FUNCTION__ << std::endl;
        va_list argsCopy;
        va_copy(argsCopy, args);
        auto size = static_cast<std::size_t>(vsnprintf(nullptr, 0, msg.c_str(), args) + 1);
        std::string str;
        str.resize(size);
        vsnprintf(&str[0], size, msg.c_str(), argsCopy);
        str.pop_back();
        return str;
    }

    static void processError(const char* msg, va_list args, 
        const std::string& errorType)
    {
        //std::cout << __PRETTY_FUNCTION__ << std::endl;
        std::string errorString;
        errorString += errorType;
        errorString += ": ";
        errorString += StringVaprintf(msg, args);

        // Print Error message once
        static std::string lastError;
        static std::mutex mtx;
        std::lock_guard<std::mutex> lock_grd(mtx);
        if(lastError != errorString)
        {
            LOG(INFO) << errorString; 
            std::cerr << errorString << std::endl;
            lastError = errorString;
        }
    }

    void Warning(const char* msg, ...)
    {
        //std::cout << __PRETTY_FUNCTION__ << std::endl;
        if(PbrtOptions.quiet) return;
        va_list args;
        va_start(args, msg);
        processError(msg, args, "Warning");
        va_end(args);
    }

    void Error(const char* msg, ...)
    {
        va_list args;
        va_start(args, msg);
        processError(msg, args, "Error");
        va_end(args);
    }

    void Warning(const std::string& msg, ...)
    {
        //std::cout << __PRETTY_FUNCTION__ << std::endl;
        if(PbrtOptions.quiet) return;
        va_list args;
        va_start(args, msg);
        processError(msg.c_str(), args, "Warning");
        va_end(args);
    }

    void Error(const std::string& msg, ...)
    {
        va_list args;
        va_start(args, msg);
        processError(msg.c_str(), args, "Error");
        va_end(args);
    }

};